//
//  BubbleSizeCalculator.swift
//  JKTools
//
//  Created by 姜奎 on 2/19/25.
//
import Cocoa

class BubbleSizeCalculator {
    static let shared = BubbleSizeCalculator()

    private let messageFont = NSFont.systemFont(ofSize: 14)
    private let horizontalPadding: CGFloat = 20
    private let bubbleInsets = NSEdgeInsets(top: 8, left: 12, bottom: 8, right: 12)

    func sizeForMessage(_ message: MessageEntity, collectionViewWidth: CGFloat) -> NSSize {

        let content = message.content.stringValue() ?? ""
            // 计算最大可用宽度
        let maxBubbleWidth = (collectionViewWidth / 2) - horizontalPadding
        let maxContentWidth = maxBubbleWidth - bubbleInsets.left - bubbleInsets.right

            // 计算文本实际宽度
        let textWidth = content.width(withFont: messageFont, maxWidth: maxContentWidth)
        let actualContentWidth = min(textWidth, maxContentWidth)

            // 计算气泡总宽度
        let bubbleWidth = actualContentWidth + bubbleInsets.left + bubbleInsets.right

            // 计算高度
        let textHeight = content.height(
            withWidth: actualContentWidth,
            font: messageFont
        )
        let totalHeight = textHeight + bubbleInsets.top + bubbleInsets.bottom + 20 // 含时间戳

        return NSSize(width: bubbleWidth, height: totalHeight)
    }
}

extension String {
    func width(withFont font: NSFont, maxWidth: CGFloat) -> CGFloat {
        let constraintRect = CGSize(width: maxWidth, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(
            with: constraintRect,
            options: .usesLineFragmentOrigin,
            attributes: [.font: font],
            context: nil
        )
        return ceil(boundingBox.width)
    }

    func height(withWidth width: CGFloat, font: NSFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(
            with: constraintRect,
            options: .usesLineFragmentOrigin,
            attributes: [.font: font],
            context: nil
        )
        return ceil(boundingBox.height)
    }
}
